# include "../include/Logger.h"
# include "../include/Log.h"
# include "../include/LogStream.h"
# include "../include/LogFile.h"
# include <iostream>
# include "../include/Work.h"

ZDSJ::Logger* ZDSJ::Logger::getInstance()
{
    static ZDSJ::Logger instance;
    return &instance;
}

const std::vector<std::string>& ZDSJ::Logger::getSupport() const
{
    return this->m_support;
}

const ZDSJ::LogStreamInterface* ZDSJ::Logger::getStreamPtr()
{
    static ZDSJ::LogStream stream;
    return &stream;
}

const ZDSJ::LogStreamInterface* ZDSJ::Logger::getStreamPtr(const std::string& _file_name, int _max_size, bool _loop, ZDSJ::OverflowStratgy _stratgy)
{
    ZDSJ::LogFile* temp = new LogFile(_file_name, _max_size, _loop, _stratgy);
    auto iter = std::find(this->m_file_stream.begin(), this->m_file_stream.end(), temp);
    if (iter != this->m_file_stream.end()) {
        delete temp;
        return *iter;
    }
    std::lock_guard<std::mutex> lock(this->m_mutex);
    iter = std::find(this->m_file_stream.begin(), this->m_file_stream.end(), temp);
    if (iter != this->m_file_stream.end()) {
        delete temp;
        return *iter;
    }
    this->m_file_stream.push_back(std::move(temp));
    return temp;
}

bool ZDSJ::Logger::empty() const
{
    return this->m_queue.size_approx() == 0;
}

bool ZDSJ::Logger::alive() const
{
    return this->m_alive;
}

void ZDSJ::Logger::work(const std::string& _log, std::vector<LogStreamInterface*> _workers)
{
    for (auto item : _workers) {
        m_queue.enqueue(new Work(_log, item));
        this->m_condition_variable.notify_one();
    }
}

void ZDSJ::Logger::threadWordFunc()
{
    bool found = false;
    while (this->m_alive) {
        std::unique_lock<std::mutex> lock(this->m_mutex);
        this->m_condition_variable.wait(lock, [&]() {
            return !this->empty() || !this->alive();
        });
        Work* one_work;
        found = this->m_queue.try_dequeue(one_work);
        if (found) {
            one_work->work();
            delete one_work;
        }
    }
}

ZDSJ::Logger::Logger()
{
    this->m_support.push_back("time");
    this->m_support.push_back("level");
    this->m_support.push_back("file");
    this->m_support.push_back("func");
    this->m_support.push_back("line");
    this->m_support.push_back("thread");
    this->m_support.push_back("message");
    this->m_alive = true;
    this->m_thread = new std::thread(&ZDSJ::Logger::threadWordFunc, this);
    
}

ZDSJ::Logger::~Logger()
{
    if (this->m_thread != nullptr) {
        this->m_alive = false;
        this->m_condition_variable.notify_one();
        this->m_thread->join();
        delete this->m_thread;
    }
    for (auto iter : this->m_file_stream) {
        delete iter;
    }
}
